home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / slip / cslip-2.6 / sunos4 / net / if_sl.c next >
Encoding:
C/C++ Source or Header  |  1992-07-25  |  24.2 KB  |  991 lines

  1. #include "sl.h"
  2. #if NSL > 0
  3. /*
  4.  * Copyright (c) 1989, 1990, 1991 Regents of the University of California.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted
  8.  * provided that the above copyright notice and this paragraph are
  9.  * duplicated in all such forms and that any documentation,
  10.  * advertising materials, and other materials related to such
  11.  * distribution and use acknowledge that the software was developed
  12.  * by the University of California, Berkeley.  The name of the
  13.  * University may not be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  *
  19.  *    Van Jacobson (van@ee.lbl.gov), Dec 31, 1989:
  20.  *    - Initial distribution.
  21.  */
  22. #ifndef lint
  23. static char rcsid[] =
  24.     "@(#) $Header: if_sl.c,v 1.19 92/07/25 22:41:33 leres Exp $ (LBL)";
  25. #endif
  26.  
  27.  
  28. /*
  29.  * Serial Line interface
  30.  *
  31.  * Originally written by
  32.  *     Rick Adams
  33.  *     Center for Seismic Studies
  34.  *     1300 N 17th Street, Suite 1450
  35.  *     Arlington, Virginia 22209
  36.  *     (703)276-7900
  37.  *     rick@seismo.css.gov
  38.  *     seismo!rick
  39.  *
  40.  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
  41.  * N.B.: this belongs in netinet, not net, the way it stands now.
  42.  * Should have a link-layer type designation, but wouldn't be
  43.  * backwards-compatible.
  44.  *
  45.  * Converted to 4.3BSD Beta by Chris Torek.
  46.  * Other changes made at Berkeley, based in part on code by Kirk Smith.
  47.  *
  48.  * Hacked almost beyond recognition by Van Jacobson (van@ee.lbl.gov).
  49.  * Added priority queuing for "interactive" traffic; hooks for TCP
  50.  * header compression; ICMP filtering (at 2400 baud, some cretin
  51.  * pinging you can use up all your bandwidth); conditionals for Sun
  52.  * OS 3.x in addition to 4.x BSD.  Made low clist behavior more robust
  53.  * and slightly less likely to hang serial line.  Sped up a bunch of
  54.  * things.
  55.  *
  56.  * The Sun OS4.x STREAMS version of this driver was written by
  57.  * Steve McCanne, Craig Leres and Van Jacobson.  The evolutionary
  58.  * ancestor of this driver was an SGI STREAMS driver written by Sam Leffler
  59.  * (which was derived, in turn, from the 4.x BSD cslip driver described
  60.  * in the previous paragraph).  However this driver bears little or
  61.  * no resemblance to Leffler's.
  62.  */
  63.  
  64. #include <sys/param.h>
  65. #include <sys/systm.h>
  66. #include <sys/mbuf.h>
  67. #include <sys/protosw.h>
  68. #include <sys/socket.h>
  69. #include <sys/errno.h>
  70. #include <sys/debug.h>
  71. #include <sys/signal.h>
  72. #include <sys/user.h>
  73. #include <sys/file.h>
  74. #include <sys/stream.h>
  75. #include <sys/stropts.h>
  76. #include <sys/termio.h>
  77. #include <net/if.h>
  78. #include <net/route.h>
  79. #include <net/netisr.h>
  80. #include <netinet/in.h>
  81. #include <netinet/in_systm.h>
  82. #include <netinet/in_var.h>
  83. #include <netinet/ip.h>
  84.  
  85. #ifdef sun
  86. #include <sys/sockio.h>
  87. #ifndef MCLFREE
  88. #define    MCLFREE(p) { \
  89.     struct mbuf mxxx; \
  90.     mxxx.m_len = MCLBYTES; \
  91.     mxxx.m_off = (int)p - (int)&mxxx; \
  92.     mxxx.m_cltype = MCL_STATIC; \
  93.     mclput(&mxxx); \
  94. }
  95. #endif
  96. #endif
  97.  
  98. #include <net/slcompress.h>
  99. #include <net/if_slvar.h>
  100. #include <net/slip.h>
  101.  
  102. #include "bpfilter.h"
  103. #if NBPFILTER > 0
  104. #include <net/bpf.h>
  105. #endif
  106.  
  107. /* XXX - next line is here for temporary error check */
  108. #include <netinet/tcp.h>
  109.  
  110. /*
  111.  * The following are patchable defaults for the three options
  112.  * in the interface flags word.  If desired, they should be set
  113.  * by config file options SL_DOCOMPRESS, SL_ALLOWCOMPRESS and
  114.  * SL_NOICMP.
  115.  *
  116.  *   sl_docompress    If = 1, compression for a line will default to "on"
  117.  *
  118.  *   sl_allowcompres    If = 1, compression for a line will default to "off"
  119.  *            but will be turned on if a compressed packet is
  120.  *            received. 
  121.  *
  122.  *   sl_noicmp        If = 1, outbound ICMP packets will be discarded.
  123.  *            XXX - shouldn't have to set this but some cretin
  124.  *            pinging us can drive our throughput to zero (not
  125.  *            to mention the raft of quenches we'll get if we're
  126.  *            unlucky enough to have to traverse the milnet.
  127.  */
  128. #ifndef SL_DOCOMPRESS
  129. #define SL_DOCOMPRESS 0
  130. #endif
  131. #ifndef SL_ALLOWCOMPRESS
  132. #define SL_ALLOWCOMPRESS 0
  133. #endif
  134. #ifndef SL_NOICMP
  135. #define SL_NOICMP 0
  136. #endif
  137. int sl_docompress = SL_DOCOMPRESS;
  138. int sl_allowcompress = SL_ALLOWCOMPRESS;
  139. int sl_noicmp = SL_NOICMP;
  140.  
  141. /*
  142.  * SLMAX is a hard limit on input packet size.  To simplify the code
  143.  * and improve performance, we require that packets fit in an mbuf
  144.  * cluster, that there be enough extra room for the ifnet header that
  145.  * IP input requires and, if we get a compressed packet, there's
  146.  * enough extra room to expand the header into a max length tcp/ip
  147.  * header (120 bytes).  If we configure up BPF, it wants an additional
  148.  * 16 bytes for the largest compressed header plus a direction byte.
  149.  * So, SLMAX can be at most
  150.  *    MCLBYTES - sizeof(struct ifnet *) - 120 - SLIP_HDRLEN
  151.  *
  152.  * If we forward a slip packet, the output routine will probably have
  153.  * to stick an ethernet (or other linklevel) header on it so we'll
  154.  * save extra mbuf allocates and copies if we leave room for that
  155.  * header whenever we stick incoming packets into an mbuf.  We need
  156.  * at least 16 bytes for that header and, if we make it twenty, the
  157.  * packet data will end up nicely aligned on machines that use 8 and
  158.  * 16 byte cache line sizes.  So, LINKHDRSPACE below is the space
  159.  * we leave for forwarded packet link level headers.
  160.  *
  161.  * SLMTU is a hard limit on output packet size.  To insure good
  162.  * interactive response, SLMTU wants to be the smallest size that
  163.  * amortizes the header cost.  (Remember that even with
  164.  * type-of-service queuing, we have to wait for any in-progress
  165.  * packet to finish.  I.e., we wait, on the average, 1/2 * mtu /
  166.  * cps, where cps is the line speed in characters per second.
  167.  * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line.  The
  168.  * average compressed header size is 6-8 bytes so any MTU > 90
  169.  * bytes will give us 90% of the line bandwidth.  A 100ms wait is
  170.  * tolerable (500ms is not), so want an MTU around 296.  (Since TCP
  171.  * will send 256 byte segments (to allow for 40 byte headers), the
  172.  * typical packet size on the wire will be around 260 bytes).  In
  173.  * 4.3tahoe+ systems, we can set an MTU in a route so we do that &
  174.  * leave the interface MTU relatively high (so we don't IP fragment
  175.  * when acting as a gateway to someone using a stupid MTU).
  176.  */
  177. #if NBPFILTER > 0
  178. #define    BUFOFFSET    (120 + sizeof(struct ifnet *) + SLIP_HDRLEN)
  179. #else
  180. #define    BUFOFFSET    (120 + sizeof(struct ifnet *))
  181. #endif
  182. #define    SLMAX        (MCLBYTES - BUFOFFSET)
  183. #ifdef LBL
  184. #define    SLMTU        576        /* LBL has per-route mtu's */
  185. #else
  186. #define    SLMTU        (512+40)
  187. #endif
  188. #define    LINKHDRSPACE    20
  189.  
  190. static    struct module_info stm_info = {
  191.     0x6963,
  192.     "slip",                /* module name */
  193.     0,                    /* minimum packet size */
  194.     INFPSZ,                /* infinite maximum packet size    */
  195.     SLMAX * 20,                /* hi-water mark */
  196.     0,                    /* lo-water mark */
  197. };
  198. void sl_rput(), sl_wput(), sl_wsrv(), sl_close();
  199. int sl_open();
  200.  
  201. static struct qinit st_rinit = {
  202.     (int (*)())sl_rput,
  203.     NULL,
  204.     sl_open,
  205.     (int (*)())sl_close,
  206.     NULL,
  207.     &stm_info,
  208.     NULL
  209. };
  210. static struct qinit st_winit = {
  211.     (int (*)())sl_wput,
  212.     (int (*)())sl_wsrv,
  213.     NULL,
  214.     NULL,
  215.     NULL,
  216.     &stm_info,
  217.     NULL
  218. };
  219. static char *st_modlist[] = {
  220.     NULL
  221. };
  222. struct streamtab if_slinfo = {
  223.     &st_rinit,
  224.     &st_winit,
  225.     NULL,
  226.     NULL,
  227.     st_modlist,
  228. };
  229.  
  230. /*
  231.  * The following disgusting hack gets around the problem that IP TOS
  232.  * can't be set in BSD/Sun/SGI OS yet.  We want to put "interactive"
  233.  * traffic on a high priority queue.  To decide if traffic is
  234.  * interactive, we check that a) it is TCP and b) one of it's ports
  235.  * if telnet, login, klogin, eklogin or ftp control.
  236.  *
  237.  * (Probably also want X/NeWS-style traffic as well.)
  238.  */
  239. static    u_short interactive_ports[16] = {
  240.     0,    513,    0,    0,    0,    21,    0,    23,
  241.     0,    2105,    0,    0,    0,    0,    0,    543
  242. };
  243. #define INTERACTIVE(p) (interactive_ports[(p) & 0xf] == (p))
  244.  
  245. /*
  246.  * Everything there is to know about if_sl interfaces
  247.  */
  248. struct sl_softc sl_softc[NSL];
  249.  
  250. #define FRAME_END        0xc0    /* Frame End */
  251. #define FRAME_ESCAPE        0xdb    /* Frame Esc */
  252. #define TRANS_FRAME_END        0xdc    /* escaped frame end */
  253. #define TRANS_FRAME_ESCAPE    0xdd    /* escaped frame esc */
  254.  
  255. int slioctl(), sloutput();
  256. void slinput();
  257.  
  258. slattach(unit)
  259.     int unit;
  260. {
  261.     register struct sl_softc *sc;
  262.     register struct ifnet *ifp;
  263.  
  264.     if (unit >= NSL)
  265.         panic("if_slinit: too many units");
  266.  
  267.     sc = &sl_softc[unit];
  268.     sc->sc_fastq.ifq_maxlen = 32;
  269.  
  270.     ifp = &sc->sc_if;
  271.     ifp->if_name = "sl";
  272.     ifp->if_unit = unit;
  273.     ifp->if_mtu = SLMTU;
  274.     ifp->if_flags = IFF_POINTOPOINT;
  275.     ifp->if_ioctl = slioctl;
  276.     ifp->if_output = sloutput;
  277.     ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  278.     if_attach(ifp);
  279. #if NBPFILTER > 0
  280.     bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
  281. #endif
  282.     printf("sl%d: attached\n", unit);
  283. }
  284.  
  285. /*
  286.  * Process ioctl from the socket side.
  287.  */
  288. int                /* 0 or error */
  289. slioctl(ifp, cmd, data)
  290.     register struct ifnet *ifp;
  291.     register int cmd;
  292.     register caddr_t data;
  293. {
  294.     register struct sl_softc *sc;
  295.     register int error = 0;
  296.     register int s;
  297.  
  298.     sc = &sl_softc[ifp->if_unit];
  299.     s = splimp();
  300.     switch (cmd) {
  301.     case SIOCSIFADDR: {
  302.         struct ifaddr *ifa = (struct ifaddr *)data;
  303.  
  304.         if (ifa->ifa_addr.sa_family != AF_INET)
  305.             error = EAFNOSUPPORT;
  306.         else if (sc->sc_rq == 0)
  307.             error = EINVAL;
  308.         else
  309.             sc->sc_if.if_flags |= IFF_UP;
  310.         break;
  311.     }
  312.     case SIOCSIFDSTADDR: {
  313.         struct ifaddr *ifa = (struct ifaddr *)data;
  314.  
  315.         if (ifa->ifa_addr.sa_family != AF_INET)
  316.             error = EAFNOSUPPORT;
  317.         break;
  318.     }
  319.     default:
  320.         error = EINVAL;
  321.         break;
  322.     }
  323.     splx(s);
  324.     return (error);
  325. }
  326.  
  327. /*
  328.  * take an mbuf chain from above and see about sending it down the stream
  329.  */
  330. int
  331. sloutput(ifp, m, dst)
  332.     register struct ifnet *ifp;
  333.     register struct mbuf *m;
  334.     register struct sockaddr *dst;
  335. {
  336.     register struct sl_softc *sc;
  337.     register struct ip *ip;
  338.     register struct ifqueue *ifq;
  339.     register int s;
  340. #if NBPFILTER > 0
  341.     u_char bpfbuf[SLMTU + SLIP_HDRLEN];
  342.     register int len;
  343. #endif
  344.  
  345.     if ((ifp->if_flags & IFF_UP) == 0) {
  346.         m_freem(m);
  347.         return (ENETDOWN);
  348.     }
  349.     if (dst->sa_family != AF_INET) {
  350.         /*
  351.          * This `cannot happen' (see slioctl).
  352.          */
  353.         printf("sl%d: af%d not supported\n", ifp->if_unit,
  354.             dst->sa_family);
  355.         m_freem(m);
  356.         return (EAFNOSUPPORT);
  357.     }
  358.     sc = &sl_softc[ifp->if_unit];
  359.  
  360. #if NBPFILTER > 0
  361.     if (sc->sc_bpf) {
  362.         /*
  363.          * We need to save the TCP/IP header before it's compressed.
  364.          * To avoid complicated code, we just copy the entire packet
  365.          * into a stack buffer (since this is a serial line, packets
  366.          * should be short and/or the copy should be negligible cost
  367.          * compared to the packet transmission time).
  368.          */
  369.         register struct mbuf *m1 = m;
  370.         register u_char *cp = bpfbuf + SLIP_HDRLEN;
  371.  
  372.         len = 0;
  373.         do {
  374.             register int mlen = m1->m_len;
  375.  
  376.             bcopy(mtod(m1, caddr_t), (caddr_t)cp, (u_int)mlen);
  377.             cp += mlen;
  378.             len += mlen;
  379.         } while (m1 = m1->m_next);
  380.     }
  381. #endif
  382.     ifq = &ifp->if_snd;
  383.     /*
  384.      * n.b.-- the `40' below checks that we have a least a min length
  385.      * tcp/ip header contiguous in an mbuf.  We don't do `sizeof' on
  386.      * some struct because too many compilers add random padding.
  387.      */
  388.     ip = mtod(m, struct ip *);
  389.     if (ip->ip_p == IPPROTO_TCP && m->m_len >= 40) {
  390.         register int p = ((int *)ip)[ip->ip_hl];
  391.  
  392.         /* do TOS queueing based on port number XXX */
  393.         if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) {
  394.             ifq = &sc->sc_fastq;
  395.             p = 1;
  396.         } else
  397.             p = 0;
  398.         if (sc->sc_if.if_flags & IFF_LINK0) {
  399.             /*
  400.              * The last parameter turns off connection id
  401.              * compression for background traffic:  Since
  402.              * fastq traffic can jump ahead of the background
  403.              * traffic, we don't know what order packets will
  404.              * go on the line.
  405.              */
  406.             p = sl_compress_tcp(m, ip, &sc->sc_comp, p);
  407.             *mtod(m, u_char *) |= p;
  408.         }
  409.     } else if (ip->ip_p == IPPROTO_ICMP &&
  410.         (sc->sc_if.if_flags & IFF_LINK2)) {
  411.         m_freem(m);
  412.         return (0);
  413.     }
  414. #if NBPFILTER > 0
  415.     if (sc->sc_bpf) {
  416.         /*
  417.          * Put the SLIP pseudo-"link header" in place.  The compressed
  418.          * header is now at the beginning of the mbuf.
  419.          */
  420.         bpfbuf[SLX_DIR] = SLIPDIR_OUT;
  421.         bcopy(mtod(m, caddr_t), (caddr_t)&bpfbuf[SLX_CHDR], CHDR_LEN);
  422.         bpf_tap(sc->sc_bpf, bpfbuf, (u_int)len + SLIP_HDRLEN);
  423.     }
  424. #endif
  425.     s = splimp();
  426.     if (IF_QFULL(ifq)) {
  427.         IF_DROP(ifq);
  428.         m_freem(m);
  429.         splx(s);
  430.         sc->sc_if.if_oerrors++;
  431.         return (ENOBUFS);
  432.     }
  433.     IF_ENQUEUE(ifq, m);
  434.     splx(s);
  435.     if (sc->sc_outmb->b_datap->db_ref == 1)
  436.         sl_wsrv(sc->sc_wq);
  437.     return (0);
  438. }
  439.  
  440. int
  441. slinit(sc)
  442.     register struct sl_softc *sc;
  443. {
  444.  
  445.     if (sc->sc_ep == (u_char *) 0) {
  446.         struct mbuf m;
  447.  
  448.         MCLGET((&m));
  449.         if (m.m_len != MCLBYTES) {
  450.             printf("sl%d: can't allocate buffer\n", sc - sl_softc);
  451.             sc->sc_if.if_flags &= ~IFF_UP;
  452.             return (0);
  453.         } else
  454.             sc->sc_ep = mtod(&m,u_char *) + (BUFOFFSET + SLMAX);
  455.     }
  456.     sc->sc_buf = sc->sc_ep - SLMAX;
  457.     sc->sc_mp = sc->sc_buf;
  458.     /*
  459.      * The STREAMS data structures and routines are so abysmally bad
  460.      * there's no way we can afford to do all the data structure
  461.      * allocation/deallocation they require per output packet.  So,
  462.      * since we only send one packet down at a time, we allocate a
  463.      * buffer & msgblk as big as we could need, set its ref cnt to 1
  464.      * (so it won't be deallocated), then copy from mbufs into it, dup
  465.      * it, and send it down for each packet.
  466.      *
  467.      * The maximum possible size is twice the MTU (every character
  468.      * could be escaped) plus two framing bytes (one on each end).
  469.      * We need two of the damn things because there's no way to
  470.      * tell the cretinous streams code that we only want to queue
  471.      * one downstream buffer -- the first one we queue is removed
  472.      * from the count (and our service procedure is called) even
  473.      * though it hasn't been output yet.
  474.      */
  475.     if ((sc->sc_outmb = allocb(2 * SLMTU + 2, BPRI_HI)) == NULL) {
  476.         printf("sl%d: can't allocate msg buffer\n", sc - sl_softc);
  477.         sc->sc_if.if_flags &= ~IFF_UP;
  478.         return (0);
  479.     }
  480.     if ((sc->sc_pendmb = allocb(2 * SLMTU + 2, BPRI_HI)) == NULL) {
  481.         printf("sl%d: can't allocate msg buffer\n", sc - sl_softc);
  482.         sc->sc_if.if_flags &= ~IFF_UP;
  483.         return (0);
  484.     }
  485.  
  486.     sc->sc_escape = 0;
  487.     sc->sc_bytessent = 0;
  488.     sc->sc_bytesrcvd = 0;
  489.  
  490.     if (sl_docompress)
  491.         sc->sc_if.if_flags |= IFF_LINK0;
  492.     else 
  493.         sc->sc_if.if_flags &=~ IFF_LINK0;
  494.     if (sl_allowcompress)
  495.         sc->sc_if.if_flags |= IFF_LINK1;
  496.     else 
  497.         sc->sc_if.if_flags &=~ IFF_LINK1;
  498.     if (sl_noicmp)
  499.         sc->sc_if.if_flags |= IFF_LINK2;
  500.     else 
  501.         sc->sc_if.if_flags &=~ IFF_LINK2;
  502.     sl_compress_init(&sc->sc_comp);
  503.     sc->sc_if.if_flags |= IFF_RUNNING;
  504.     return (1);
  505. }
  506.  
  507. /*
  508.  * XXX should probably be in net/if.c.
  509.  */
  510. static void
  511. if_rtdelete(ifp)
  512.     register struct ifnet *ifp;
  513. {
  514.     register struct ifaddr *ifa = ifp->if_addrlist;
  515.     struct rtentry route;
  516.  
  517.     for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) {
  518.         bzero((caddr_t)&route, sizeof (route));
  519.         route.rt_dst = ifa->ifa_dstaddr;
  520.         route.rt_gateway = ifa->ifa_addr;
  521.         route.rt_flags = RTF_HOST|RTF_UP;
  522.         (void) rtrequest(SIOCDELRT, &route);
  523.     }
  524. }
  525.  
  526. /*
  527.  * open SLIP STREAMS module
  528.  */
  529. /* ARGSUSED */
  530. int
  531. sl_open(rq, dev, flag, sflag)
  532.     register queue_t *rq;
  533.     register dev_t dev;
  534.     register int flag;
  535.     register int sflag;
  536. {
  537.     register struct sl_softc *sc;
  538.     register queue_t *wq = WR(rq);
  539.     register int i, s;
  540.  
  541.     if (MODOPEN != sflag)
  542.         return (OPENFAIL);
  543.     if (rq->q_ptr != 0)
  544.         return (0);
  545.     if (u.u_uid != 0) {    /* for now, only root can add links */
  546.         u.u_error = EPERM;
  547.         return (OPENFAIL);
  548.     }
  549.     sc = &sl_softc[0];
  550.     s = splstr();
  551.     for (i = NSL; --i >= 0; sc++)
  552.         if (sc->sc_rq == 0) {
  553.             if (!slinit(sc)) {
  554.                 u.u_error = ENOBUFS;
  555.                 goto bad;
  556.             }
  557.             sc->sc_rq = rq;
  558.             sc->sc_wq = wq;
  559.             rq->q_ptr = (caddr_t)sc;
  560.             wq->q_ptr = (caddr_t)sc;
  561.             splx(s);
  562.             return (0);
  563.         }
  564.     u.u_error = EBUSY;
  565. bad:
  566.     splx(s);
  567.     return (OPENFAIL);
  568. }
  569.  
  570. /*
  571.  * Flush input or output.
  572.  */
  573. void
  574. sl_flush(op, rq, wq)
  575.     register u_char op;
  576.     register queue_t *rq;
  577.     register queue_t *wq;
  578. {
  579.     register struct sl_softc *sc = (struct sl_softc *)rq->q_ptr;
  580.     register int s;
  581.  
  582.     if (op & FLUSHW) {
  583.         /* flush outbound packets */
  584.         register struct ifqueue *q;
  585.         register struct mbuf *m;
  586.  
  587.         s = splimp();
  588.         q = &sc->sc_fastq;
  589.         while (1) {
  590.             IF_DEQUEUE(q, m);
  591.             if (m == NULL)
  592.                 break;
  593.             IF_DROP(q);
  594.             m_freem(m);
  595.         }
  596.         q = &sc->sc_if.if_snd;
  597.         while (1) {
  598.             IF_DEQUEUE(q, m);
  599.             if (m == NULL)
  600.                 break;
  601.             IF_DROP(q);
  602.             m_freem(m);
  603.         }
  604.         splx(s);
  605.         s = splstr();
  606.         flushq(wq, FLUSHALL);
  607.         splx(s);
  608.     }
  609.     if (op & FLUSHR) {
  610.         /* flush partially received packet */
  611.         s = splstr();
  612.         flushq(rq, FLUSHALL);
  613.         sc->sc_buf = sc->sc_ep - SLMAX;
  614.         sc->sc_mp = sc->sc_buf;
  615.         sc->sc_escape = 0;
  616.         splx(s);
  617.     }
  618. }
  619.  
  620. void
  621. sl_close(rq)
  622.     register queue_t *rq;
  623. {
  624.     register struct sl_softc *sc = (struct sl_softc *)rq->q_ptr;
  625.     register int s;
  626.  
  627.     sl_flush(FLUSHRW, rq, sc->sc_wq);
  628.     s = splimp();
  629.     if_rtdelete(&sc->sc_if);
  630.     if_down(&sc->sc_if);
  631.     sc->sc_wq->q_ptr = 0;
  632.     rq->q_ptr = 0;
  633.     sc->sc_rq = 0;
  634.     sc->sc_wq = 0;
  635.     if (sc->sc_outmb)
  636.         freeb(sc->sc_outmb);
  637.     if (sc->sc_pendmb)
  638.         freeb(sc->sc_pendmb);
  639.     if (sc->sc_ep)
  640.         MCLFREE((struct mbuf *)(sc->sc_ep - (SLMAX + BUFOFFSET)));
  641.     sc->sc_ep = 0;
  642.     sc->sc_mp = 0;
  643.     sc->sc_buf = 0;
  644.     sc->sc_if.if_flags &=~ IFF_RUNNING;
  645.     splx(s);
  646. }
  647.  
  648. /*
  649.  * handle streams packets from the stream head.  They should be only IOCTLs.
  650.  */
  651. void
  652. sl_wput(wq, bp)
  653.     register queue_t *wq;
  654.     register mblk_t *bp;
  655. {
  656.     register struct sl_softc *sc = (struct sl_softc*)wq->q_ptr;
  657.  
  658.     switch (bp->b_datap->db_type) {
  659.     case M_DATA:            /* data does not come this way */
  660.     case M_DELAY:            /* do not allow random controls */
  661.         return;
  662.     case M_FLUSH:
  663.         sl_flush(*bp->b_rptr, sc->sc_rq, wq);
  664.         break;
  665.     case M_IOCTL:
  666.         if (((struct iocblk *)bp->b_rptr)->ioc_cmd == SLIOGUNIT) {
  667.             register struct iocblk *ioc =
  668.                            (struct iocblk *)bp->b_rptr;
  669.             bp->b_datap->db_type = M_IOCACK;
  670.             if (bp->b_cont)
  671.                 freemsg(bp->b_cont);
  672.             bp->b_cont = allocb(sizeof(int), BPRI_HI);
  673.             *(int *)bp->b_cont->b_wptr = sc->sc_if.if_unit;
  674.             bp->b_cont->b_wptr += sizeof(int);
  675.             ioc->ioc_count = sizeof(int);
  676.             ioc->ioc_error = 0;
  677.             qreply(wq, bp);
  678.             return;
  679.         }
  680.         break;
  681.     }
  682.     putnext(wq, bp);
  683. }
  684.  
  685. /*
  686.  * Accept a new STREAMS message from the serial line.
  687.  */
  688. void
  689. sl_rput(rq, bp)
  690.     register queue_t *rq;
  691.     register mblk_t *bp;
  692. {
  693.     register struct sl_softc *sc = (struct sl_softc*)rq->q_ptr;
  694.  
  695.     switch (bp->b_datap->db_type) {
  696.     case M_DATA:
  697.         if ((sc->sc_if.if_flags & IFF_UP) == 0)
  698.             freemsg(bp);
  699.         else {
  700.             register mblk_t *tp;
  701.             register u_char *buf = bp->b_rptr;
  702.  
  703.             do {
  704.                 slinput(sc, buf, bp->b_wptr - buf);
  705.                 tp = bp->b_cont;
  706.                 freeb(bp);
  707.             } while (bp = tp);
  708.         }
  709.         return;
  710.     case M_FLUSH:
  711.         sl_flush(*bp->b_rptr, rq, sc->sc_wq);
  712.         break;
  713.     }
  714.     putnext(rq, bp);
  715. }
  716.  
  717. /*
  718.  * Copy data buffer to mbuf chain; add ifnet pointer.
  719.  */
  720. struct mbuf *
  721. sl_btom(sc, len)
  722.     register struct sl_softc *sc;
  723.     register int len;
  724. {
  725.     register u_char *cp;
  726.     register struct mbuf *m;
  727.  
  728.     MGET(m, M_DONTWAIT, MT_DATA);
  729.     if (m == NULL)
  730.         return (NULL);
  731.  
  732.     /*
  733.      * If we have more than MLEN bytes, it's cheaper to
  734.      * queue the cluster we just filled & allocate a new one
  735.      * for the input buffer.  Otherwise, fill the mbuf we
  736.      * allocated above.  Note that code in the input routine
  737.      * guarantees that packet + ifp will fit in a cluster and
  738.      * initial setup left room for interface pointer.
  739.      */
  740.     cp = sc->sc_buf;
  741.     if (len > MLEN - LINKHDRSPACE) {
  742.         MCLGET(m);
  743.         if (m->m_len != MCLBYTES) {
  744.             /* we couldn't get a cluster - if memory's this
  745.              * low, it's time to start dropping packets. */
  746.             m_freem(m);
  747.             return (NULL);
  748.         }
  749.         sc->sc_ep = mtod(m, u_char *) + (BUFOFFSET + SLMAX);
  750.         m->m_off = (int)cp - (int)m - sizeof(struct ifnet *);
  751.     } else {
  752.         m->m_off = MMINOFF + LINKHDRSPACE - sizeof(struct ifnet *);
  753.         bcopy((caddr_t)cp, (caddr_t)&m->m_dat[LINKHDRSPACE], (u_int)len);
  754.     }
  755.     m->m_len = len + sizeof(struct ifnet *);
  756.     *mtod(m, struct ifnet **) = &sc->sc_if;
  757.     return (m);
  758. }
  759.  
  760. /*
  761.  * convert buffer of data into packets.
  762.  */
  763. void
  764. slinput(sc, buf, buflen)
  765.     register struct sl_softc *sc;
  766.     register u_char *buf;
  767.     register int buflen;
  768. {
  769.     register struct mbuf *m;
  770.     register int len;
  771.     register int s;
  772.     register int c;
  773. #if NBPFILTER > 0
  774.     u_char chdr[CHDR_LEN];
  775. #endif
  776.  
  777.     while (--buflen >= 0) {
  778.         ++sc->sc_bytesrcvd;
  779.         c = *buf++;
  780.         switch (c) {
  781.  
  782.         case TRANS_FRAME_ESCAPE:
  783.             if (sc->sc_escape)
  784.                 c = FRAME_ESCAPE;
  785.             break;
  786.  
  787.         case TRANS_FRAME_END:
  788.             if (sc->sc_escape)
  789.                 c = FRAME_END;
  790.             break;
  791.  
  792.         case FRAME_ESCAPE:
  793.             sc->sc_escape = 1;
  794.             continue;
  795.  
  796.         case FRAME_END:
  797.             len = sc->sc_mp - sc->sc_buf;
  798.             if (len < 3)
  799.                 /* less than min length packet - ignore */
  800.                 goto newpack;
  801. #if NBPFILTER > 0
  802.             if (sc->sc_bpf)
  803.                 /*
  804.                  * Save the compressed header, so we can
  805.                  * tack it on later.  Note that we just
  806.                  * copy the maximum number of bytes (16) --
  807.                  * we will end up copying garbage in some
  808.                  * cases but this is okay.  We remember
  809.                  * where the buffer started so we can
  810.                  * compute the new header length.
  811.                  */
  812.                 bcopy((caddr_t)sc->sc_buf, (caddr_t)chdr,
  813.                       CHDR_LEN);
  814. #endif
  815.             if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) {
  816.                 if (c & 0x80)
  817.                     c = TYPE_COMPRESSED_TCP;
  818.                 else if (c == TYPE_UNCOMPRESSED_TCP)
  819.                     *sc->sc_buf &= 0x4f;
  820.                 /*
  821.                  * we've got something that's not an IP packet.
  822.                  * If compression is enabled, try to uncompress
  823.                  * it.  Otherwise, if `auto-enable' compression
  824.                  * is on and it's a reasonable packet,
  825.                  * uncompress it then enable compression.
  826.                  * Otherwise, drop it.
  827.                  */
  828.                 if (sc->sc_if.if_flags & IFF_LINK0) {
  829.                     len = sl_uncompress_tcp(&sc->sc_buf,
  830.                                 len, (u_int)c,
  831.                                 &sc->sc_comp);
  832.                     if (len <= 0)
  833.                         goto error;
  834.                 } else if ((sc->sc_if.if_flags & IFF_LINK1) &&
  835.                        c == TYPE_UNCOMPRESSED_TCP &&
  836.                        len >= 40) {
  837.                     len = sl_uncompress_tcp(&sc->sc_buf,
  838.                                 len, (u_int)c,
  839.                                 &sc->sc_comp);
  840.                     if (len <= 0)
  841.                         goto error;
  842.                     sc->sc_if.if_flags |= IFF_LINK0;
  843.                 } else
  844.                     goto error;
  845.             }
  846. #if NBPFILTER > 0
  847.             if (sc->sc_bpf) {
  848.                 /* 
  849.                  * Put the SLIP pseudo-"link header" in place.
  850.                  * We couldn't do this any earlier since 
  851.                  * decompression probably moved the buffer
  852.                  * pointer.  Then, invoke BPF.
  853.                  */
  854.                 register u_char *hp = sc->sc_buf - SLIP_HDRLEN;
  855.                 hp[SLX_DIR] = SLIPDIR_IN;
  856.                 bcopy((caddr_t)chdr, (caddr_t)&hp[SLX_CHDR],
  857.                       CHDR_LEN);
  858.                 bpf_tap(sc->sc_bpf, hp, (u_int)len + SLIP_HDRLEN);
  859.             }
  860. #endif
  861.             m = sl_btom(sc, len);
  862.             if (m == NULL)
  863.                 goto error;
  864.  
  865.             sc->sc_if.if_ipackets++;
  866.             s = splimp();
  867.             if (IF_QFULL(&ipintrq)) {
  868.                 IF_DROP(&ipintrq);
  869.                 sc->sc_if.if_ierrors++;
  870.                 m_freem(m);
  871.             } else {
  872.                 IF_ENQUEUE(&ipintrq, m);
  873.                 schednetisr(NETISR_IP);
  874.             }
  875.             splx(s);
  876.             goto newpack;
  877.         }
  878.         if (sc->sc_mp < sc->sc_ep) {
  879.             *sc->sc_mp++ = c;
  880.             sc->sc_escape = 0;
  881.             continue;
  882.         }
  883.     error:
  884.         sc->sc_if.if_ierrors++;
  885.     newpack:
  886.         sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX;
  887.         sc->sc_escape = 0;
  888.     }
  889. }
  890.  
  891. /*
  892.  * Copy exactly one packet to the stream below us (any more and our
  893.  * type-of-service queuing turns into a nop).
  894.  */
  895. void
  896. sl_wsrv(wq)
  897.     register queue_t *wq;
  898. {
  899.     register struct sl_softc *sc = (struct sl_softc *)wq->q_ptr;
  900.     register struct mbuf *m;
  901.     register u_char *op;
  902.     register u_char *basep;
  903.     register int s;
  904.     register int len;
  905.  
  906.     s = splstr();
  907.     if (sc->sc_outmb->b_datap->db_ref != 1) {
  908.         wq->q_next->q_flag |= QWANTW;
  909.         splx(s);
  910.         return;
  911.     }
  912.  
  913.     /*
  914.      * Get a packet and send it to the interface.
  915.      */
  916.     (void) splimp();
  917.     IF_DEQUEUE(&sc->sc_fastq, m);
  918.     if (m == NULL)
  919.         IF_DEQUEUE(&sc->sc_if.if_snd, m);
  920.     splx(s);
  921.     if (m == NULL)
  922.         return;
  923.  
  924.     /*
  925.      * The extra FRAME_END will start up a new packet, and thus
  926.      * will flush any accumulated garbage.
  927.      */
  928.     op = basep = sc->sc_outmb->b_datap->db_base;
  929.     *op++ = FRAME_END;
  930.  
  931.     while (m) {
  932.         register u_char *cp;
  933.         register u_char *ep;
  934.         register u_char c;
  935.         register struct mbuf *m2;
  936.  
  937.         cp = mtod(m, u_char *);
  938.         ep = cp + m->m_len;
  939.         while (cp < ep) {
  940.             switch (c = *cp++) {
  941.  
  942.             case FRAME_ESCAPE:
  943.                 *op++ = FRAME_ESCAPE;
  944.                 c = TRANS_FRAME_ESCAPE;
  945.                 break;
  946.  
  947.             case FRAME_END:
  948.                 *op++ = FRAME_ESCAPE;
  949.                 c = TRANS_FRAME_END;
  950.             }
  951.             *op++ = c;
  952.         }
  953.         MFREE(m, m2);
  954.         m = m2;
  955.     }
  956.     *op++ = FRAME_END;
  957.     len = op - basep;
  958.     sc->sc_bytessent += len;
  959.     sc->sc_if.if_opackets++;
  960.     {
  961.         register mblk_t *bp;
  962.  
  963.         /* swap current & pending output buffers */
  964.         bp = sc->sc_outmb;
  965.         sc->sc_outmb = sc->sc_pendmb;
  966.         sc->sc_pendmb = bp;
  967.  
  968.         bp = dupb(bp);
  969.         if (bp == NULL) {
  970.             /*
  971.              * out of buffers -- flush everything so the
  972.              * next packet will force us to try again or
  973.              * we'll hang this line.
  974.              */
  975.             sl_flush(FLUSHW, sc->sc_rq, wq);
  976.             sc->sc_if.if_collisions++;
  977.         } else {
  978.             /*
  979.              * send block downstream, trying to make sure
  980.              * that we get a callback when it has been picked off.
  981.              */
  982.             bp->b_wptr += len;
  983.             s = splstr();
  984.             wq->q_next->q_flag |= QWANTW;
  985.             splx(s);
  986.             putnext(wq, bp);
  987.         }
  988.     }
  989. }
  990. #endif
  991.